package com.xmim.server.session;

import com.xmim.core.constants.MessageConstants;
import com.xmim.core.entity.UserDetail;
import com.xmim.core.session.user.AbstractUserSession;
import com.xmim.core.session.user.UserSession;
import com.xmim.fulcrum.FulcrumFactory;
import com.xmim.server.util.ChannelUtil;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelMetadata;
import io.netty.channel.local.LocalAddress;
import io.netty.util.AttributeKey;
import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.net.SocketAddress;

/**
 * 实现服务器Socket Session会话
 */
@Slf4j
public class DefaultLocalSession extends AbstractUserSession {


    public static final AttributeKey<String> KEY_USER_ID = AttributeKey.valueOf("key_user_id");


    public DefaultLocalSession(FulcrumFactory fulcrumFactory, String sessionId) {
        super(fulcrumFactory, sessionId);
    }

    public static UserSession getSession(Channel channel) {
        return channel.attr(ChannelUtil.KEY_LOCAL_SESSION).get();
    }

    public static UserDetail getUser(Channel channel) {
        return channel.attr(ChannelUtil.KEY_LOCAL_SESSION_USER).get();
    }

    @Override
    protected void onBind() {
        Channel channel = (Channel) this.getContext();
        InetSocketAddress ipSocket = (InetSocketAddress) channel.remoteAddress();
        this.addAttribute(ATTR_HOST, ipSocket.getHostString());
        this.addAttribute(ATTR_HOST_NAME, ipSocket.getHostName());
        this.addAttribute(ATTR_PORT, ipSocket.getPort());
        channel.attr(ChannelUtil.KEY_LOCAL_SESSION).set(this);
        channel.attr(ChannelUtil.KEY_LOCAL_SESSION_USER).set(getUser());
    }

    @Override
    protected void checkContext(Object context) {
        if (!Channel.class.isAssignableFrom(context.getClass())) {
            throw new IllegalArgumentException(MessageConstants.INVALID_HANDLER);
        }
    }

    //写Protobuf数据帧
    @Override
    public synchronized DefaultLocalSession writeAndFlush(Object pkg) {
        ((Channel) this.getContext()).writeAndFlush(pkg);
        return this;
    }

    //写Protobuf数据帧
    @Override
    public synchronized DefaultLocalSession writeAndClose(Object pkg) {
        ((Channel) this.getContext()).writeAndFlush(pkg);
        close();
        return this;
    }

    //关闭连接
    @Override
    public synchronized DefaultLocalSession close() {
        //用户下线 通知其他节点
        ChannelFuture future = ((Channel) this.getContext()).close();
        future.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture future) throws Exception {
                if (!future.isSuccess()) {
                    log.error("CHANNEL_CLOSED error ");
                }
            }
        });
        return this;
    }

    @Override
    public boolean isValid() {
        Channel channel = (Channel) this.getContext();
        return channel != null && channel.isOpen();
    }

    @Override
    public AbstractUserSession setUser(UserDetail user) {
        super.setUser(user);
        ((Channel) this.getContext()).attr(ChannelUtil.KEY_LOCAL_SESSION_USER).set(getUser());
        return this;
    }
}
